from src.netWork.OOP.Network import Network as Network
from functools import reduce
from src.netWork.OOP.Connection import Connection as Connection


def gradient_check(network, sample_feature, sample_label):
    network: Network
    '''
    检查梯度，运用差商检验梯度是否小于10的-4次
    :param network: 神经网络对象
    :param sample_feature: 样本的特征
    :param sample_label: 样本的标签
    :return:
    '''
    network_error = lambda vec1, vec2: 0.5 * reduce(lambda a, b: a + b,
                                                    map(lambda v: (v[0] - v[1]) * (v[0] - v[1]), zip(vec1, vec2)))

    network.get_gradient(sample_feature,sample_label)

    #检查每个权重
    conn: Connection
    for conn in network.connections.connections:
        # 获取指定连接的梯度
        actual_gradient = conn.get_gradient()

        # 增加一个很小的值，计算网络的误差
        epsilon = 0.0001
        conn.weight += epsilon

        error1 = network_error(network.predict(sample_feature), sample_label)

        #减去一个很小的值，计算网络的误差
        conn.weight -= 2*epsilon
        error2 = network_error(network.predict(sample_feature), sample_label)

        #
        expected_gradient = (error2 - error1)/ (2*epsilon)

        print('expected gradient: \t%f\nactual gradient: \t%f' % (
            expected_gradient, actual_gradient))